package cn.jbolt.core.kit;

import com.alibaba.ttl.TransmittableThreadLocal;
import com.jfinal.kit.StrKit;

import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * saas 租户保存当前租户信息用的工具类
 * @ClassName:  JBoltSaasTenantKit
 * @author: JFinal学院-小木 QQ：909854136
 * @date:   2022年2月20日
 *
 */
public class JBoltSaasTenantKit {
	public static JBoltSaasTenantKit me = new JBoltSaasTenantKit();
	/**
	 * 针对JBolt平台saas模式租户JBoltSaasTenant的ThreadLocal
	 */
	private final TransmittableThreadLocal<JBoltSaasTenant> jboltTenantTL = new TransmittableThreadLocal<JBoltSaasTenant>();

	private static JBoltSaasTenantSnToIdProcessor _snToIdProcessor = null;
	private static JBoltSaasTenantSnToNameProcessor _snToNameProcessor = null;
	private static JBoltSaasTenantIdToSnProcessor _idToSnProcessor = null;
	private static JBoltSaasTenantIdToNameProcessor _idToNameProcessor = null;
	private static JBoltSaasTenantAccessibleProcessor _accessibleProcessor = null;
	private static JBoltSaasTenantGetAllProcessor _getAllTenantsProcessor = null;


	/**
	 * 设置SN转ID处理器
	 * @param processor
	 */
	public void setSnToIdProcessor(JBoltSaasTenantSnToIdProcessor processor) {
		_snToIdProcessor = processor;
	}
	/**
	 * 设置SN转Name处理器
	 * @param processor
	 */
	public void setSnToNameProcessor(JBoltSaasTenantSnToNameProcessor processor) {
		_snToNameProcessor = processor;
	}
	/**
	 * 设置ID转Name处理器
	 * @param processor
	 */
	public void setIdToNameProcessor(JBoltSaasTenantIdToNameProcessor processor) {
		_idToNameProcessor = processor;
	}
	/**
	 * 设置Accessible处理器
	 * @param processor
	 */
	public void setAccessibleProcessor(JBoltSaasTenantAccessibleProcessor processor) {
		_accessibleProcessor = processor;
	}
	/**
	 * 设置ID转Sn处理器
	 * @param processor
	 */
	public void setIdToSnProcessor(JBoltSaasTenantIdToSnProcessor processor) {
		_idToSnProcessor = processor;
	}

	/**
	 * 设置获取所有租户列表的处理器
	 * @param processor
	 */
	public void setGetAllTenantsProcessor(JBoltSaasTenantGetAllProcessor processor) {
		_getAllTenantsProcessor = processor;
	}

	/**
	 * 总部模拟租户调用
	 * @param sn
	 * @return
	 */
	public JBoltSaasTenantKit useBySn(String sn) {
		Objects.requireNonNull(sn, "sn can not be null");
		JBoltSaasTenant tenant = JBoltSaasTenant.createBySn(sn);
		tenant.setId(processIdBySn(sn));
		tenant.setName(processNameBySn(sn));
		tenant.setSelfRequest(false);
		String errorMsg = processAccessible(tenant.getId());
		tenant.setErrorMsg(errorMsg);
		tenant.setAccessible(errorMsg == null);
		jboltTenantTL.set(tenant);
		return me;
	}
	/**
	 * 总部模拟租户调用
	 * @param id
	 * @return
	 */
	public JBoltSaasTenantKit useById(Object id) {
		Objects.requireNonNull(id, "id can not be null");
		JBoltSaasTenant tenant = JBoltSaasTenant.createById(id);
		tenant.setSn(processSnById(id));
		tenant.setName(processNameById(id));
		tenant.setSelfRequest(false);
		String errorMsg = processAccessible(id);
		tenant.setErrorMsg(errorMsg);
		tenant.setAccessible(errorMsg == null);
		jboltTenantTL.set(tenant);
		return me;
	}

	/**
	 * 租户自己调用
	 * @param sn
	 * @return
	 */
	public JBoltSaasTenantKit self(String sn) {
		Objects.requireNonNull(sn, "sn can not be null");
		JBoltSaasTenant tenant = JBoltSaasTenant.createBySn(sn);
		tenant.setId(processIdBySn(sn));
		tenant.setName(processNameBySn(sn));
		tenant.setSelfRequest(true);
		String errorMsg = processAccessible(tenant.getId());
		tenant.setErrorMsg(errorMsg);
		tenant.setAccessible(errorMsg == null);
		jboltTenantTL.set(tenant);
		return me;
	}

	/**
	 * 处理通过ID 拿到Accessible
	 * @param id
	 * @return
	 */
	public String processAccessible(Object id) {
		if(_accessibleProcessor == null) {
			throw new RuntimeException("JBoltSaasTenantKit 未设置Accessible处理器");
		}
		return _accessibleProcessor.process(id);
	}
	/**
	 * 模拟调用
	 * @param <T>
	 * @param function
	 * @return
	 */
	public <T> T call(Supplier<T> function) {
		try {
			return function.get();
		} finally {
			clear();
		}
	}
	/**
	 * 模拟调用
	 * @param func
	 */
	public void call(JBoltSaasTenantFunction func) {
		try {
			func.call();
		} finally {
			clear();
		}
	}

	/**
	 * 删除租户
	 */
	public void clear() {
		jboltTenantTL.remove();
	}


	/**
	 * 获得当前租户tenant
	 * @return
	 */
	public JBoltSaasTenant get() {
		return jboltTenantTL.get();
	}

	/**
	 * 获得当前租户Sn
	 * @return
	 */
	public String getSn() {
		JBoltSaasTenant tenant = get();
		return tenant == null?null:tenant.getSn();
	}
	/**
	 * 获得当前租户name
	 * @return
	 */
	public String getName() {
		JBoltSaasTenant tenant = get();
		return tenant == null?null:tenant.getName();
	}
	/**
	 * 获得当前租户ID
	 * @return
	 */
	public Object getId() {
		JBoltSaasTenant tenant = get();
		return tenant == null?null:tenant.getId();
	}
	/**
	 * 获得当前租户ID
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T getIdAs() {
		return (T) getId();
	}

	/**
	 * 获得当前租户ID
	 * @return
	 */
	public String getIdToStr() {
		Object id = getId();
		return id==null?null:id.toString();
	}
	/**
	 * 当前是租户请求
	 * @return
	 */
	public boolean isSelfRequest() {
		JBoltSaasTenant tenant = get();
		return tenant != null && tenant.isSelfRequest();
	}

	/**
	 * 获得当前租户ID 转 Integer
	 * @return
	 */
	public Integer getIdToInt() {
		Object id = getId();
		if(id == null) {return null;}
		if(id instanceof Integer) {
			return (Integer) id;
		}
		return Integer.parseInt(id.toString());
	}

	/**
	 * 获得当前租户ID 转 Long
	 * @return
	 */
	public Long getIdToLong() {
		Object id = getId();
		if(id == null) {return null;}
		if(id instanceof Long) {
			return (Long) id;
		}
		return Long.parseLong(id.toString());
	}


	/**
	 *根据SN处理ID
	 * @param sn
	 */
	public Object processIdBySn(String sn) {
		if(_snToIdProcessor == null) {
			throw new RuntimeException("JBoltSaasTenantKit 未设置SN to ID处理器");
		}
		return _snToIdProcessor.process(sn);
	}

	/**
	 *根据SN处理name
	 * @param sn
	 */
	public String processNameBySn(String sn) {
		if(_snToNameProcessor == null) {
			throw new RuntimeException("JBoltSaasTenantKit 未设置SN to Name处理器");
		}
		return _snToNameProcessor.process(sn);
	}

	/**
	 *根据ID处理name
	 * @param id
	 * @return
	 */
	public String processNameById(Object id) {
		if(_idToNameProcessor == null) {
			throw new RuntimeException("JBoltSaasTenantKit 未设置ID to Name处理器");
		}
		return _idToNameProcessor.process(id);
	}

	/**
	 *根据ID处理SN
	 * @param id
	 * @return
	 */
	public String processSnById(Object id) {
		if(_idToSnProcessor == null) {
			throw new RuntimeException("JBoltSaasTenantKit 未设置ID to SN处理器");
		}
		return _idToSnProcessor.process(id);
	}

	/**
	 * 获得所有租户信息
	 * @return
	 */
	public List<JBoltSaasTenant> getAllSaasTenants() {
		if(_getAllTenantsProcessor == null) {
			throw new RuntimeException("JBoltSaasTenantKit 未设置_getAllTenantsProcessor处理器");
		}
		return _getAllTenantsProcessor.get();
	}

	/**
	 * 获得所有可用可访问租户信息
	 * @return
	 */
	public List<JBoltSaasTenant> getAccessibleSaasTenants() {
		List<JBoltSaasTenant> tenants = getAllSaasTenants();
		if(tenants!=null && tenants.size()>0){
			return tenants.stream().filter(t->t.isAccessible()).collect(Collectors.toList());
		}
		return tenants;
	}

	/**
	 * 当前有租户在访问 或者被模拟访问
	 * @return
	 */
	public boolean isOk() {
		return null!=get();
	}

	/**
	 * 租户是否可访问
	 * @return
	 */
	public boolean isAccessible() {
		JBoltSaasTenant tenant = get();
		return tenant != null && tenant.isAccessible();
	}
	/**
	 * 租户错误信息
	 * @param defaultValue
	 * @return
	 */
	public String getErrorMsg(String defaultValue) {
		JBoltSaasTenant tenant = get();
		return tenant == null?(StrKit.isBlank(defaultValue)?null:defaultValue):StrKit.defaultIfBlank(tenant.getErrorMsg(), defaultValue);
	}

}
